// File: cell.cpp
// Author: Ilkka Vuorio

// Description: Implementation of class Cell.

#include <assert.h>

#include "cell.h"
#include "sudoku.h"

Cell::Cell()
{
    clear();
}

bool Cell::setValue(int value)
{
    if (value < 1 || value > DOMAIN_SIZE)
        return false;

    m_value = value;
    m_has_value = true;
    m_candidates.clear();

    return true;
}

bool Cell::hasValue(int value) const
{
    if (m_has_value == true && m_value == value)
        return true;
    else
        return false;
}

bool Cell::getValue(int& value) const
{
    if (!m_has_value)
        return false;

    value = m_value;

    assert(value >= 1 && value <= DOMAIN_SIZE);
    assert(m_candidates.size() == 0);

    return true;
}

int Cell::getCandidateCount() const
{
    int count = m_candidates.size();

    assert(count >= 0 && count <= DOMAIN_SIZE);

    return count;
}

int Cell::getCandidate(int i) const
{
    assert(i >= 0);
    assert(i < getCandidateCount());

    int candidate = m_candidates[i];
    assert(candidate >= 1 && candidate <= DOMAIN_SIZE);
    return candidate;
}

bool Cell::hasCandidate(int candidate) const
{
    for (unsigned int i = 0; i < m_candidates.size(); i++)
    {
        if (m_candidates[i] == candidate)
            return true;
    }
    return false;
}

bool Cell::deleteCandidate(int candidate)
{
    unsigned int n = m_candidates.size();
    for (unsigned int i = 0; i < n; i++)
    {
        if (m_candidates[i] == candidate)
        {
            m_candidates.erase(m_candidates.begin() + i);
            assert(m_candidates.size() == n - 1);
            assert(this->hasCandidate(candidate) == false);
            return true;
        }
    }
    return false;
}

bool Cell::promoteSingleCandidate()
{
    if (m_has_value)
        return false;

    if (m_candidates.size() != 1)
        return false;

    int single_candidate = m_candidates[0];

    bool value_was_set = setValue(single_candidate);
    assert(value_was_set == true);
    
    return true;
}

void Cell::clear()
{
    m_has_value= false;

    m_candidates.clear();
    for (int candidate = 1; candidate <= DOMAIN_SIZE; candidate++)
        m_candidates.push_back(candidate);
}

bool Cell::runUnitTest()
{
    Cell cell;
    
    // A blank Cell should have fully populated candidate list
    int candidate_count = cell.getCandidateCount();
    if (candidate_count != DOMAIN_SIZE)
        return false;

    // All possible candidates should be on the list (no duplicates)
    for (int candidate = 1; candidate <= DOMAIN_SIZE; candidate++)
        if (cell.hasCandidate(candidate) != true)
            return false;

    bool retval;
    int value = 0;

    // Cell doesn't have a value yet
    retval = cell.getValue(value);
    if (retval != false)
        return false;

    // Can't set the value to 0
    retval = cell.setValue(value);
    if (retval != false)
        return false;

    // Cell still doesn't have a value
    retval = cell.getValue(value);
    if (retval != false)
        return false;

    // Should be possible to set value to 1
    value = 1;
    retval = cell.setValue(value);
    if (retval != true)
        return false;

    // Once value is set, candidate list is empty
    candidate_count = cell.getCandidateCount();
    if (candidate_count != 0)
        return false;

    // hasCandidate should return false 
    for (int candidate = 1; candidate <= DOMAIN_SIZE; candidate++)
        if (cell.hasCandidate(candidate) != false)
            return false;

    value = 2;

    // getValue should return true, because value was set earlier
    retval = cell.getValue(value);
    if (retval != true)
        return false;

    // Cell value was set to 1
    if(value != 1)
        return false;

    return true;
}